/*! \file
 * \brief Enter a brief description here.
 *
 * Enter a detailed description here. (optional)
 * \author Author (Ivo Wingelaar)
 * \date Date (2011)
 * \version Version (0.0.1)
 * \copyright Copyright (GNU LGPL v3)
 */

#ifndef __LYNX_VIDEO_MANAGER_C_HPP_INCLUDED__
#define __LYNX_VIDEO_MANAGER_C_HPP_INCLUDED__

#include "LynxVideoManager.hpp"
#include "LynxTimeManager.hpp"
#include "LynxWindowManagerWindows_C.hpp"
#include "LynxWindowManagerLinux_C.hpp"
#include "LynxFPSCounter.hpp"
#include "LynxExtensionHandler.hpp"
#include "LynxTexture_C.hpp"
#include <map>

namespace Lynx
{

enum E_RENDER_MODE
{
    ERM_NONE = 0,
    ERM_2D,
    ERM_3D,
};

class VideoManager_C : public VideoManager, public GPUProgrammingServices, public MaterialRendererServices, public OpenGLExtensionHandler
{
public:
#ifdef _LYNX_WINDOWS_
    VideoManager_C(WindowManagerWindows_C* dev, const Myth::Math::Vector2u screenSize);
#endif // _LYNX_WINDOWS_

#ifdef _LYNX_LINUX_
    VideoManager_C(WindowManagerLinux_C* dev, const Myth::Math::Vector2u screensize);
#endif // _LYNX_LINUX_

    bool init_driver();

    ///////////////////
    virtual void toggle_v_sync(bool on);
    ///////////////////

    bool generic_driver_init(const Myth::Math::Vector2u screenSize, bool stencilBuffer);

    void create_material_renderers();

    //! destructor
    virtual ~VideoManager_C();

    virtual bool begin_scene(bool backBuffer=true, bool zBuffer=true,
                            Color color=Color(255,0,0,0),
                            Myth::Math::Rectanglei* sourceRect=0);

    virtual bool end_scene();

    //! Disable a feature of the driver.
    virtual void set_feature(E_VIDEO_MANAGER_FEATURE feature, bool flag=true);

    //! queries the features of the driver, returns true if feature is available
    virtual bool query_feature(E_VIDEO_MANAGER_FEATURE feature) const;

    //! sets transformation
    virtual void set_transform(E_TRANSFORMATION_STATE state, const Myth::Math::Matrix4 mat);

    //! sets a material
    virtual void set_material(const Material material);

    //! loads a Texture
    virtual Texture* get_texture(const std::string filename);

    //! Returns a texture by index
    virtual Texture* get_texture_by_index(uint32_t index);

    //! Returns amount of textures currently loaded
    virtual uint32_t get_texture_count() const;

    //! Renames a texture
    virtual void rename_texture(Texture* texture, const std::string newName);

    //! creates a Texture
    virtual Texture* add_texture(const Myth::Math::Vector2u size, const std::string name, E_COLOR_FORMAT format = ECF_A8R8G8B8);

    virtual bool set_render_target(Texture* texture, bool clearBackBuffer = true, bool clear_z_buffer = true, Color color = Color(0,0,0,0));

    virtual bool set_render_target(E_RENDER_TARGET target, bool clearTarget = true, bool clear_z_buffer = true, Color color = Color(0,0,0,0));

    virtual bool set_render_target(const std::vector<RenderTarget> texture, bool clearBackBuffer = true, bool clear_z_buffer = true, Color color = Color(0,0,0,0));

    virtual void set_clip_rectangle(Myth::Math::Rectanglei *clip = 0);

    virtual const Myth::Math::Rectanglei* get_clip_rectangle(void) const;

    //! sets a viewport
    virtual void set_view_port(const Myth::Math::Rectanglei area);

    //! gets the area of the current viewport
    virtual const Myth::Math::Rectanglei get_view_port() const;

    virtual void draw_vertex_primitive_list(const void* vertices, uint32_t vertexCount, const void* indexList, uint32_t primCount, E_VERTEX_TYPE vType = EVT_STANDARD, E_PRIMITIVE_TYPE pType = EPT_TRIANGLES, E_INDEX_TYPE iType = EIT_16BIT);

    virtual void draw_2d_vertex_primitive_list(const void* vertices, uint32_t vertexCount, const void* indexList, uint32_t primCount, E_VERTEX_TYPE vType = EVT_STANDARD, E_PRIMITIVE_TYPE pType = EPT_TRIANGLES, E_INDEX_TYPE iType = EIT_16BIT);

    virtual void draw_3d_line(const Myth::Math::Vector3f start, const Myth::Math::Vector3f end, Color color = Color(255,255,255,255));

    virtual void draw_3d_triangle(const Myth::Math::Triangle3f triangle, Color color = Color(255,255,255,255));

    virtual void draw_3d_box(const Myth::Math::BoundingBox3f box, Color color = Color(255,255,255,255));

    virtual void draw_2d_image(const Texture* texture, const Myth::Math::Vector2i destPos);

    //! draws a set of 2d images, using a color and the alpha
    /** channel of the texture if desired. The images are drawn
    beginning at pos and concatenated in one line. All drawings
    are clipped against clipRect (if != 0).
    The subtextures are defined by the array of sourceRects
    and are chosen by the indices given.
    \param texture: Texture to be drawn.
    \param pos: Upper left 2d destination position where the image will be drawn.
    \param sourceRects: Source rectangles of the image.
    \param indices: List of indices which choose the actual rectangle used each time.
    \param kerningWidth: offset on position
    \param clipRect: Pointer to rectangle on the screen where the image is clipped to.
    This pointer can be 0. Then the image is not clipped.
    \param color: Color with which the image is colored.
    Note that the alpha component is used: If alpha is other than 255, the image will be transparent.
    \param useAlphaChannelOfTexture: If true, the alpha channel of the texture is
    used to draw the image. */
    virtual void draw_2d_image_batch(const Texture* texture, const Myth::Math::Vector2i pos, const std::vector<Myth::Math::Rectanglei> sourceRects, const std::vector<int32_t> indices, int32_t kerningWidth = 0, Color color = Color(255,255,255,255), bool useAlphaChannelOfTexture=false);

    //! Draws a set of 2d images, using a color and the alpha channel of the texture.
    /** All drawings are clipped against clipRect (if != 0).
    The subtextures are defined by the array of sourceRects and are
    positioned using the array of positions.
    \param texture Texture to be drawn.
    \param pos Array of upper left 2d destinations where the images
    will be drawn.
    \param sourceRects Source rectangles of the image.
    \param clipRect Pointer to rectangle on the screen where the
    images are clipped to.
    If this pointer is 0 then the image is not clipped.
    \param color Color with which the image is drawn.
    Note that the alpha component is used. If alpha is other than
    255, the image will be transparent.
    \param useAlphaChannelOfTexture: If true, the alpha channel of
    the texture is used to draw the image. */
    virtual void draw_2d_image_batch(const Texture* texture, const std::vector<Myth::Math::Vector2i> positions, const std::vector<Myth::Math::Rectanglei> sourceRects, Color color=Color(255,255,255,255), bool useAlphaChannelOfTexture=false);

    //! Draws a 2d image, using a color (if color is other then Color(255,255,255,255)) and the alpha channel of the texture if wanted.
    virtual void draw_2d_image(const Texture* texture, const Myth::Math::Vector2i destPos, const Myth::Math::Rectanglei sourceRect, Color color=Color(255,255,255,255), bool useAlphaChannelOfTexture=false);

    //! Draws a part of the texture into the rectangle.
    virtual void draw_2d_image(const Texture* texture, const Myth::Math::Rectanglei destRect, const Myth::Math::Rectanglei sourceRect, const Color* const colors=0, bool useAlphaChannelOfTexture=false);

    //! Draws a 2d rectangle
    virtual void draw_2d_rectangle(Color color, const Myth::Math::Rectanglei pos);

    virtual void draw_2d_rectangle(const Myth::Math::Rectanglei pos, Color colorLeftUp, Color colorRightUp, Color colorLeftDown, Color colorRightDown);

    virtual void draw_2d_rectangle_outline(const Myth::Math::Rectanglei pos, Color color=Color(255,255,255,255));

    //! Draws a 2d line.
    virtual void draw_2d_line(const Myth::Math::Vector2i start, const Myth::Math::Vector2i end, Color color=Color(255,255,255,255));

    virtual void draw_2d_lines(std::vector<Myth::Math::Line2i> mLines, Color color=Color(255,255,255,255));

    virtual void draw_pixel(uint32_t x, uint32_t y, const Color color);

    virtual void draw_2d_polygon(Myth::Math::Vector2i center, float radius, Color color=Color(100,255,255,255), int32_t vertexCount = 10);

    virtual void set_fog(Color color = Color(0,255,255,255), E_FOG_TYPE fogType = EFT_FOG_LINEAR, float start=50.0f, float end=100.0f, float density=0.01f, bool pixelFog=false, bool rangeFog=false);

    virtual void get_fog(Color& color, E_FOG_TYPE& fogType, float& start, float& end, float& density, bool& pixelFog, bool& rangeFog);

    virtual E_COLOR_FORMAT get_color_format() const;

    //! get screen size
    virtual const Myth::Math::Vector2u get_screen_size() const;

    virtual const Myth::Math::Vector2u get_current_render_target_size() const;

    virtual int32_t get_fps() const;

    virtual uint32_t get_primitive_count_drawn(uint32_t mode = 0) const;

    //! deletes all dynamic lights there are
    virtual void delete_all_dynamic_lights();

    //! adds a dynamic light, returning an index to the light
    //! \param light: the light data to use to create the light
    //! \return An index to the light, or -1 if an error occurs
    virtual int32_t add_dynamic_light(const Light light);

    //! Turns a dynamic light on or off
    //! \param lightIndex: the index returned by add_dynamic_light
    //! \param turnOn: true to turn the light on, false to turn it off
    virtual void turn_light_on(int32_t lightIndex, bool turnOn);

    //! returns the maximal amount of dynamic lights the device can handle
    virtual uint32_t get_maximal_dynamic_light_amount() const;

    //! Sets the dynamic ambient light color. The default color is
    //! (0,0,0,0) which means it is dark.
    //! \param color: New color of the ambient light.
    virtual void set_ambient_light(const Colorf color);

    //! Returns current amount of dynamic lights set
    //! \return Current amount of dynamic lights set
    virtual uint32_t get_dynamic_light_count() const;

    //! Returns light data which was previously set with IVideDriver::add_dynamic_light().
    //! \param idx: Zero based index of the light. Must be greater than 0 and smaller
    //! than IVideoDriver()::get_dynamic_light_count.
    //! \return Light data.
    virtual const Light get_dynamic_light(uint32_t idx) const;

    //! Removes a texture from the texture cache and deletes it, freeing lot of
    //! memory.
    virtual void remove_texture(Texture* texture);

    //! Removes all texture from the texture cache and deletes them, freeing lot of
    //! memory.
    virtual void remove_all_textures();

    //! Creates a render target texture.
    virtual Texture* add_render_target_texture(const Myth::Math::Vector2u size, std::string name = "rt", const E_COLOR_FORMAT format = ECF_UNKNOWN);

    //! Returns the maximum amount of primitives (mostly vertices) which
    //! the device is able to render with one draw_indexed_triangle_list
    //! call.
    virtual uint32_t get_maximum_primitive_count() const;

    //! Enables or disables a texture creation flag.
    virtual void set_texture_creation_flag(E_TEXTURE_CREATION_FLAG flag, bool enabled);

    //! Returns if a texture creation flag is enabled or disabled.
    virtual bool get_texture_creation_flag(E_TEXTURE_CREATION_FLAG flag) const;

    virtual Image* create_image(Texture* texture, const Myth::Math::Vector2i pos, const Myth::Math::Vector2u size);

    //! Draws a mesh buffer
    virtual void draw_mesh_buffer(const MeshBuffer* mb);

    void set_wrap_mode(const Material& material);

    GLint get_texture_wrap_mode(const uint8_t clamp);

protected:
    struct HWBufferLink
    {
        HWBufferLink(const MeshBuffer* _MeshBuffer) :
            mMeshBuffer(_MeshBuffer),
            mChangedID_Vertex(0),
            mChangedID_Index(0),
            mLastUsed(0),
            mMapped_Vertex(EHM_NEVER),
            mMapped_Index(EHM_NEVER)
        {
            if(mMeshBuffer)
                mMeshBuffer->increment_counter();
        }

        virtual ~HWBufferLink()
        {
            if(mMeshBuffer)
                mMeshBuffer->decrement_counter();
        }

        const MeshBuffer* mMeshBuffer;
        uint32_t mChangedID_Vertex;
        uint32_t mChangedID_Index;
        uint32_t mLastUsed;
        E_HARDWARE_MAPPING mMapped_Vertex;
        E_HARDWARE_MAPPING mMapped_Index;
    };

    //! Gets hardware buffer link from a meshbuffer (may create or update buffer)
    virtual HWBufferLink* get_buffer_link(const MeshBuffer* mb);

    //! updates hardware buffer if needed  (only some drivers can)
    virtual bool update_hardware_buffer(HWBufferLink* HWBuffer);

    //! Create hardware buffer from mesh (only some drivers can)
    virtual HWBufferLink* create_hardware_buffer(const MeshBuffer* mb);

    //! Draw hardware buffer (only some drivers can)
    virtual void draw_hardware_buffer(HWBufferLink* HWBuffer);

    //! Update all hardware buffers, remove unused ones
    virtual void update_all_hardware_buffers();

    //! Delete hardware buffer
    virtual void delete_hardware_buffer(HWBufferLink* HWBuffer);

    //! Remove hardware buffer
    virtual void remove_hardware_buffer(const MeshBuffer* mb);

    //! Remove all hardware buffers
    virtual void remove_all_hardware_buffers();

    //! is vbo recommended on this mesh?
    virtual bool is_hardware_buffer_recommended(const MeshBuffer* mb);

public:
    //! Only used by the engine internally.
    /** Used to notify the driver that the window was resized. */
    virtual void on_resize(const Myth::Math::Vector2u size);

    virtual int32_t add_material_renderer(MaterialRenderer* renderer, const char* name =0);

    //! Returns the transformation set by set_transform
    virtual const Myth::Math::Matrix4 get_transform(E_TRANSFORMATION_STATE state) const;

    //! Returns pointer to the IGPUProgrammingServices interface.
    virtual GPUProgrammingServices* get_gpu_programming_services();

    //! Returns pointer to material renderer or null
    virtual MaterialRenderer* get_material_renderer(uint32_t idx);

    //! Returns amount of currently available material renderers.
    virtual uint32_t get_material_renderer_count() const;

    //! Returns name of the material renderer
    virtual const char* get_material_renderer_name(uint32_t idx) const;

    virtual int32_t add_high_level_shader_material(const char* vertexShaderProgram, const char* vertexShaderEntryPointName,
            E_VERTEX_SHADER_TYPE vsCompileTarget,
            const char* pixelShaderProgram,
            const char* pixelShaderEntryPointName,
            E_PIXEL_SHADER_TYPE psCompileTarget,
            const char* geometryShaderProgram,
            const char* geometryShaderEntryPointName = "main",
            E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0,
            E_PRIMITIVE_TYPE inType = EPT_TRIANGLES,
            E_PRIMITIVE_TYPE outType = EPT_TRIANGLE_STRIP,
            uint32_t verticesOut = 0,
            ShaderConstantSetCallBack* callback = 0,
            E_MATERIAL_TYPE baseMaterial = EMT_SOLID,
            int32_t userData = 0);

    //! Like IGPUProgrammingServices::add_shader_material(), but loads from files.
    /** \param vertexShaderProgram: Text file handle containing the source
    of the vertex shader program. Set to 0 if no vertex shader shall be
    created.
    \param vertexShaderEntryPointName: Name of the entry function of the
    vertexShaderProgram
    \param vsCompileTarget: Vertex shader version the high level shader
    shall be compiled to.
    \param pixelShaderProgram: Text file handle containing the source of
    the pixel shader program. Set to 0 if no pixel shader shall be created.
    \param pixelShaderEntryPointName: Entry name of the function of the
    pixelShaderEntryPointName
    \param psCompileTarget: Pixel shader version the high level shader
    shall be compiled to.
    \param geometryShaderProgram: Text file handle containing the source of
    the geometry shader program. Set to 0 if no geometry shader shall be
    created.
    \param geometryShaderEntryPointName: Entry name of the function of the
    geometryShaderEntryPointName
    \param gsCompileTarget: Geometry shader version the high level shader
    shall be compiled to.
    \param inType Type of vertices passed to geometry shader
    \param outType Type of vertices created by geometry shader
    \param verticesOut Maximal number of vertices created by geometry
    shader. If 0, maximal number supported is assumed.
    \param callback: Pointer to an implementation of
    IShaderConstantSetCallBack in which you can set the needed vertex and
    pixel shader program constants. Set this to 0 if you don't need this.
    \param baseMaterial: Base material which renderstates will be used to
    shade the material.
    \param userData: a user data int. This int can be set to any value and
    will be set as parameter in the callback method when calling
    on_set_constants(). In this way it is easily possible to use the same
    callback method for multiple materials and distinguish between them
    during the call.
    \return Number of the material type which can be set in
    SMaterial::MaterialType to use the renderer. -1 is returned if an
    error occured, e.g. if a shader program could not be compiled or a
    compile target is not reachable. The error strings are then printed to
    the error log and can be catched with a custom event receiver. */
    virtual int32_t add_high_level_shader_material_from_files(
        Myth::Stream::Input* vertexShaderProgram,
        const char* vertexShaderEntryPointName,
        E_VERTEX_SHADER_TYPE vsCompileTarget,
        Myth::Stream::Input* pixelShaderProgram,
        const char* pixelShaderEntryPointName,
        E_PIXEL_SHADER_TYPE psCompileTarget,
        Myth::Stream::Input* geometryShaderProgram,
        const char* geometryShaderEntryPointName = "main",
        E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0,
        E_PRIMITIVE_TYPE inType = EPT_TRIANGLES,
        E_PRIMITIVE_TYPE outType = EPT_TRIANGLE_STRIP,
        uint32_t verticesOut = 0,
        ShaderConstantSetCallBack* callback = 0,
        E_MATERIAL_TYPE baseMaterial = EMT_SOLID,
        int32_t userData = 0);

    //! Adds a new ASM shader material renderer to the VideoDriver
    /** Note that it is a good idea to call IVideoDriver::query_feature() in
    advance to check if the IVideoDriver supports the vertex and/or pixel
    shader version your are using.

    The material is added to the VideoDriver like with
    IVideoDriver::add_material_renderer() and can be used like it had been
    added with that method.
    \param vertexShaderProgram: String containing the source of the vertex
    shader program. This can be 0 if no vertex program shall be used.

    For DX8 programs, the will always input registers look like this: v0:
    position, v1: normal, v2: color, v3: texture cooridnates, v4: texture
    coordinates 2 if available.

    For DX9 programs, you can manually set the registers using the dcl_
    statements.
    \param pixelShaderProgram: String containing the source of the pixel
    shader program. This can be 0 if you don't want to use a pixel shader.
    \param callback: Pointer to an implementation of
    IShaderConstantSetCallBack in which you can set the needed vertex and
    pixel shader program constants. Set this to 0 if you don't need this.
    \param baseMaterial: Base material which renderstates will be used to
    shade the material.
    \param userData: a user data int. This int can be set to any value and
    will be set as parameter in the callback method when calling
    on_set_constants(). In this way it is easily possible to use the same
    callback method for multiple materials and distinguish between them
    during the call.
    \return Returns the number of the material type which can be set in
    SMaterial::MaterialType to use the renderer. -1 is returned if an
    error occured. -1 is returned for example if a vertex or pixel shader
    program could not be compiled, the error strings are then printed out
    into the error log, and can be catched with a custom event receiver. */
    virtual int32_t add_shader_material(const char* vertexShaderProgram = 0,
                                      const char* pixelShaderProgram = 0,
                                      ShaderConstantSetCallBack* callback = 0,
                                      E_MATERIAL_TYPE baseMaterial = EMT_SOLID,
                                      int32_t userData = 0);

    //! Like IGPUProgrammingServices::add_shader_material(), but loads from files.
    /** \param vertexShaderProgram: Text file containing the source of the
    vertex shader program. Set to 0 if no shader shall be created.
    \param pixelShaderProgram: Text file containing the source of the pixel
    shader program. Set to 0 if no shader shall be created.
    \param callback: Pointer to an IShaderConstantSetCallback object to
    which the on_set_constants function is called.
    \param baseMaterial: baseMaterial
    \param userData: a user data int. This int can be set to any value and
    will be set as parameter in the callback method when calling
    on_set_constants(). In this way it is easily possible to use the same
    callback method for multiple materials and distinguish between them
    during the call.
    \return Returns the number of the material type which can be set in
    SMaterial::MaterialType to use the renderer. -1 is returned if an
    error occured. -1 is returned for example if a vertex or pixel shader
    program could not be compiled, the error strings are then printed out
    into the error log, and can be catched with a custom event receiver. */
    virtual int32_t add_shader_material_from_files(Myth::Stream::Input* vertexShaderProgram,
            Myth::Stream::Input* pixelShaderProgram,
            ShaderConstantSetCallBack* callback = 0,
            E_MATERIAL_TYPE baseMaterial = EMT_SOLID,
            int32_t userData = 0);

    //! Returns a pointer to the mesh manipulator.
    virtual MeshManipulator* get_mesh_manipulator();

    //! Clears the ZBuffer.
    virtual void clear_z_buffer();

    //! Returns an image created from the last rendered frame.
    virtual Image* create_screen_shot();

    //! Sets the name of a material renderer.
    virtual void set_material_renderer_name(int32_t idx, const char* name);

    //! looks if the image is already loaded
    virtual Texture* find_texture(const std::string filename);

    virtual bool set_clip_plane(uint32_t index, const Myth::Math::Plane3f plane, bool enable = false);

    virtual void enable_clip_plane(uint32_t index, bool enable);

    void upload_clip_plane(uint32_t index);

    //! Returns the graphics card vendor name.
    virtual std::string get_vender_info()
    {
        return "Not available on this driver.";
    }

    //! Set the minimum number of vertices for which a hw buffer will be created
    /** \param count Number of vertices to set as minimum. */
    virtual void set_min_hardware_buffer_vertex_count(uint32_t count);

    //! Get the global Material, which might override local materials.
    /** Depending on the enable flags, values from this Material
    are used to override those of local materials of some
    meshbuffer being rendered. */
    virtual OverrideMaterial& get_override_material();

    //! Get the 2d override material for altering its values
    virtual Material& get_material_2d();

    //! Enable the 2d override material
    virtual void enable_material_2d(bool enable=true);

    //! Only used by the engine internally.
    virtual void set_allow_z_write_on_transparent(bool flag)
    {
        mAllowZWriteOnTransparent=flag;
    }

    //! Returns the maximum texture size supported.
    virtual Myth::Math::Vector2u get_max_texture_size() const;

    //! Can be called by an IMaterialRenderer to make its work easier.
    virtual void set_basic_render_states(const Material& material, const Material& lastmaterial, bool resetAllRenderstates);

    //! Sets a vertex shader constant.
    virtual void set_vertex_shader_constant(const float* data, int32_t startRegister, int32_t constantAmount=1);

    //! Sets a pixel shader constant.
    virtual void set_pixel_shader_constant(const float* data, int32_t startRegister, int32_t constantAmount=1);

    //! Sets a constant for the vertex shader based on a name.
    virtual bool set_vertex_shader_constant(const char* name, const float* floats, int count);

    //! Sets a constant for the pixel shader based on a name.
    virtual bool set_pixel_shader_constant(const char* name, const float* floats, int count);

    virtual VideoManager* get_video_manager();

    virtual LogManager* get_log_manager() const;

    //! sets the current Texture
    //! Returns whether setting was a success or not.
    bool set_active_texture(uint32_t stage, const Texture* texture);

    Texture* create_depth_texture(Texture* texture, bool shared=true);
    void remove_depth_texture(Texture* texture);

    //! disables all textures beginning with the optional fromStage parameter. Otherwise all texture stages are disabled.
    //! Returns whether disabling was successful or not.
    bool disable_textures(uint32_t fromStage = 0);

    //! Convert E_PRIMITIVE_TYPE to OpenGL equivalent
    GLenum primitive_type_to_gl(E_PRIMITIVE_TYPE type) const;

    //! sets the needed renderstates
    void set_render_states_3d_mode();

    //! sets the needed renderstates
    void set_render_states_2d_mode(bool alpha, bool texture, bool alphaChannel);

    inline void create_gl_matrix(GLfloat gl_matrix[16], const Myth::Math::Matrix4& m);

    inline void create_gl_texture_matrix(GLfloat* o, const Myth::Math::Matrix4& m);

    void clear_buffers(bool backBuffer, bool zBuffer, bool stencilBuffer, Color color);

    void create_color_buffer(const void* vertices, uint32_t vertexCount, E_VERTEX_TYPE vType);

    void render_array(const void* indexList, uint32_t primitiveCount, E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType);

    void assign_hardware_light(uint32_t lightIndex);

protected:
    //! deletes all textures
    void delete_all_textures();

    //! adds a surface, not loaded or created by the Irrlicht Engine
    void add_texture(Texture* surface);

    //! Creates a texture from a loaded IImage.
    virtual Texture* add_texture(const std::string name, Image* image, void* mipmapData = 0);

    //! checks triangle count and print warning if wrong
    bool check_primitive_count(uint32_t prmcnt) const;

    // adds a material renderer and drops it afterwards. To be used for internal creation
    int32_t add_and_drop_material_renderer(MaterialRenderer* m);

    //! deletes all material renderers
    void delete_material_renderers();

    // prints renderer version
    void print_version();

    struct HWBufferLink_opengl : public HWBufferLink
    {
        HWBufferLink_opengl(const MeshBuffer* _MeshBuffer) :
            HWBufferLink(_MeshBuffer),
            vbo_verticesID(0),
            vbo_indicesID(0)
        {
            //
        }

        GLuint vbo_verticesID; //tmp
        GLuint vbo_indicesID; //tmp

        GLuint vbo_verticesSize; //tmp
        GLuint vbo_indicesSize; //tmp
    };

    bool update_vertex_hardware_buffer(HWBufferLink_opengl* HWBuffer);

    bool update_index_hardware_buffer(HWBufferLink_opengl* HWBuffer);

    struct Surface
    {
        Texture* mSurface;

        bool operator < (const Surface& other) const
        {
            return mSurface->get_name() < other.mSurface->get_name();
        }
    };

    struct SMaterialRenderer
    {
        MaterialRenderer* mRenderer;
        std::string mName;
    };

    TimeManager* mTimeManager;
    LogManager* mLogManager;

    std::vector<Surface> mTextures;
    std::vector<Light> mLights;
    std::vector<SMaterialRenderer> mMaterialRenderers;

    std::map<const MeshBuffer* , HWBufferLink*> mHWBufferMap;

    //! mesh manipulator
    MeshManipulator* mMeshManipulator;

    Myth::Math::Rectanglei mViewPort;
    Myth::Math::Vector2u mScreenSize;
    Myth::Math::Matrix4 mTransformationMatrix;

    FPSCounter mFPSCounter;

    uint32_t mPrimitivesDrawn;
    uint32_t mMinVertexCountForVBO;

    uint32_t mTextureCreationFlags;

    float mFogStart;
    float mFogEnd;
    float mFogDensity;
    Color mFogColor;

    OverrideMaterial mOverrideMaterial;
    Material mOverrideMaterial2D;
    Material mInitMaterial2D;
    bool mOverrideMaterial2DEnabled;

    E_FOG_TYPE mFogType;
    bool mPixelFog;
    bool mRangeFog;
    bool mAllowZWriteOnTransparent;

    bool mFeatureEnabled[EVMF_COUNT];

    std::string mName;
    Myth::Math::Matrix4 mMatrices[ETS_COUNT];
    std::vector<uint8_t> mColorBuffer;

    E_RENDER_MODE mCurrentRenderMode;
    bool mResetRenderStates;
    bool mTransformation3DChanged;
    uint8_t mAntiAlias;

    Material mMaterial, mLastMaterial;
    Texture_C* mRenderTargetTexture;
    const Texture* mCurrentTexture[8];
    std::vector<Texture*> mDepthTextures;
    Myth::Math::Rectanglei mClipRectangle;

    struct UserClipPlane
    {
        UserClipPlane() :
            mEnabled(false)
        {
            //
        }

        Myth::Math::Plane3f mPlane;
        bool mEnabled;
    };

    std::vector<UserClipPlane> mUserClipPlanes;
    Myth::Math::Vector2u mCurrentRendertargetSize;
    std::string mVendorName;
    Myth::Math::Matrix4 mTextureFlipMatrix;

    E_COLOR_FORMAT mColorFormat;
    E_RENDER_TARGET mCurrentTarget;

    struct RequestedLight
    {
        RequestedLight(Light const& lightData) :
            mLightData(lightData),
            mHardwareLightIndex(-1),
            mDesireToBeOn(true)
        {
            //
        }

        Light mLightData;
        int32_t mHardwareLightIndex;
        bool mDesireToBeOn;
    };

    std::vector<RequestedLight> mRequestedLights;

#ifdef _LYNX_WINDOWS_
    HDC mHDc;
    HGLRC mHglrc;
    HWND mWindow;
    WindowManagerWindows_C* mDevice;
#endif // _LYNX_WINDOWS_

#ifdef _LYNX_LINUX_
    GLXDrawable mDrawable;
    GLXContext mX11Context;
    Window mX11Window;
    Display* mX11Display;
    WindowManagerLinux_C* mDevice;
#endif  // _LYNX_LINUX_
};


} // namespace Lynx

#endif // __LYNX_VIDEO_MANAGER_C_HPP_INCLUDED__
